package org.fjsei.yewu.controller;

import io.camunda.tasklist.dto.Pagination;
import io.camunda.tasklist.dto.Task;
import io.camunda.tasklist.dto.TaskList;
import io.camunda.zeebe.client.ZeebeClient;
import io.camunda.zeebe.client.api.response.ActivatedJob;
import io.camunda.zeebe.client.api.response.ProcessInstanceEvent;
//import io.camunda.zeebe.spring.client.lifecycle.ZeebeClientLifecycle;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.DeclareError;
import org.fjsei.yewu.bpm.UniversalProcessVariables;
import org.fjsei.yewu.bpm.IncidentProcessListService;
import org.fjsei.yewu.bpm.UserTaskListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;
import io.camunda.operate.model.Incident;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@Slf4j
@ConditionalOnBean(ZeebeClient.class)
@RestController
public class FlowUniversalRestApi {
    //@Autowired    private ZeebeClient zeebeClient;
    @Autowired
    private ZeebeClient client;
    @Autowired
    private UserTaskListService userTaskListService;
    @Autowired
    private IncidentProcessListService incidentProcessListService;

    //public ResponseEntity<String> startTweetReviewProcess(ServerWebExchange exchange) {}
    @PutMapping("/tweet")
    public ResponseEntity<String> startReportReviewProcess() {
        String author="herzhang";
        String boss="herzhang";
        String message="会冲突吗？";
        //有延迟： 这里发起流程之后：大约10秒钟才能在TaskList网页上面看见到的。
        String reference = startReportReviewProcess(author, message, boss);
        log.info("起点要推消息 作者{} 审核人：{} ： {}", author, boss, message);
        // And just return something for the sake of the example
        return ResponseEntity
                .status(HttpStatus.OK)
                .body("Started process instance " + reference);
    }
    /**每个UserTask都要配置的自定义头部：用户任务目标授权用户assignee 或授权用户组s candidateGroups;
     * 若BPMN文件定义如此的：candidateGroups="=[bossg,tomens]" 必须映射这两个用户组。
     * 【规定】用户组名字不要含有","逗号[和]的三个；可以直接给BPMN定义文件设置单一个变量名:assignGroups,拼接授权用户组字符串[bossg,tomens]。
     * */
    @Deprecated(since="测试用")
    public String startReportReviewProcess(String author, String uri, String boss) {
        UniversalProcessVariables processVariables = new UniversalProcessVariables().setAuthor(author).setUri(uri).setApprover(boss);
        //processVariables.setBossg(boss);
      //  processVariables.setAssignGroups(List.of("审核小组",boss));     //特殊数组变量  2019-10-02T08:09:40+08:00
        //processVariables.setExpirationDate("2022-06-27T11:05:00+08:00");
        //processVariables.setCreationDate("2022-06-27T11:03:00+08:00");  前后都用"2022-06-27T11:03:00"可以
        Instant instant=Instant.now();
      //  processVariables.setCreationDate(instant.toString());
        //多实例子流程 assingee=ispMens[loopCounter] 序号不要loopCounter-1,它是1开始的不是0;
        processVariables.setIspMens(List.of("admin2","herzhang"));
        processVariables.setSubitem(false);
        //只能用字符串表达时间变量；     3分钟之后
        processVariables.setExpirationDate(instant.plus(30, ChronoUnit.MINUTES).toString());


        ProcessInstanceEvent processInstance = client.newCreateInstanceCommand()
                .bpmnProcessId("ReportApproval")
                .latestVersion()
                .variables(processVariables)
                .send().join();// blocking call!

        return String.valueOf( processInstance.getProcessInstanceKey() );
    }

    @PutMapping("/claim_approv")
    public ResponseEntity<String> approvalReportReviewProcess() {
        // And then retrieve the UserTask and complete it with 'approved = true'
        Long keyId=waitForUserTaskAndComplete("herzhang", Collections.singletonMap("approved", true));

        // And just return something for the sake of the example
        return ResponseEntity
                .status(HttpStatus.OK)
                .body("Started process instance " + keyId);
    }
    @PutMapping("/claim_approv2")
    public ResponseEntity<String> approvalReportReviewProcess2() {
        // And then retrieve the UserTask and complete it with 'approved = true'
        Long keyId=waitForUserTaskAndComplete("admin2", Collections.singletonMap("approved", true));

        // And just return something for the sake of the example
        return ResponseEntity
                .status(HttpStatus.OK)
                .body("Started process instance " + keyId);
    }
    @Deprecated
    //按流程环节查找：根据jobType找更为底层通用的ActivatedJob：用户组和授权用户实际这个层次根本不关心的。userTaskId="user_task_review_tweet","user_task_handle_duplicate"
    public Long waitForUserTaskAndComplete2(String userTaskId, Map<String, Object> variables){
        String jobType="io.camunda.zeebe:userTask";     //若=USER_TASK_JOB_TYPE="io.camunda.zeebe:userTask";两个节点都能查出来user_task_handle_duplicate user_task_review_tweet节点
        //改="user_task_review_tweet" "Handle duplicate tweet" "io.camunda.zeebe:userTask:Review tweet"查不到！
        List<ActivatedJob> jobs = client.newActivateJobsCommand().jobType(jobType).maxJobsToActivate(10).workerName("waitForUserTaskAndComplete").send().join().getJobs();
        log.info("jobs！ActivatedJob, 队列有：{}", jobs.size());
        // Should be only one
        assertTrue(jobs.size()>0, "Job for user task '" + userTaskId + "' does not exist");
        ActivatedJob userTaskJob = jobs.get(0);
        // Make sure it is the right one
        if (userTaskId!=null) {
            assertEquals(userTaskId, userTaskJob.getElementId());
        }

        // And complete it passing the variables
        if (variables!=null && variables.size()>0) {
            client.newCompleteCommand(userTaskJob.getKey()).variables(variables).send().join();
        } else {
            client.newCompleteCommand(userTaskJob.getKey()).send().join();
        }
        return userTaskJob.getKey();
    }
    @Deprecated
    /**测试REST才用的：
     * 按登录用户的用户组查找适合的任务
     * 单步调试导致的：io.grpc.StatusRuntimeException: DEADLINE_EXCEEDED: deadline exceeded after 19.999678100s. [closed=[], open=[[remote_addr=/127.0.0.1:26500]]]
     * */
    public Long waitForUserTaskAndComplete(String userId, Map<String, Object> variables){
        //List<ActivatedJob> jobs = client.newActivateJobsCommand().jobType(jobType).maxJobsToActivate(10).workerName("waitForUserTaskAndComplete").send().join().getJobs();
        Pagination page=new Pagination.Builder().pageSize(20).build();
        TaskList jobs= userTaskListService.fetchMyUserTask(userId,page);       //,List.of("用graphQL","dfd")
        log.info("jobs！ActivatedJob, 队列有：{}", jobs.size());
        assertTrue(jobs.size()>0, "Job for user task '" + userId + "' does not exist");
        Task userTaskJob = jobs.get(0);
        //todo: 正常这里分开的两个操作！
        //完成本环节用户任务
        if (variables!=null && variables.size()>0) {
            client.newCompleteCommand(Long.parseLong(userTaskJob.getId())).variables(variables).send().join();
        } else {
          //client.newCompleteCommand(userTaskJob.getKey()).send().join();
        }
        return Long.parseLong(userTaskJob.getId());
    }
    /**维护者：看故障流程，前端还没有对应的列表页面。
     * 测试可用的，或者维护管理员使用的；
     * */
    @GetMapping("/problems")
    public ResponseEntity<String> searchProcessProblems() {
        List<Incident>  problems= incidentProcessListService.getIncidents(20);
        log.info("有问题流程需后台处理, 队列有：{}", problems.size());
        return ResponseEntity
                .status(HttpStatus.OK)
                .body("Problem process 队列有： " + problems.size());
    }
}
